/**
 * @brief 设备管理主程序
 * @version 1.0
 * @date
 * @author 宋炜
*/
#include <curl/curl.h>
#include <unistd.h>
#include <sys/reboot.h>
#include <memory.h>
#include <string.h>
#include <regex>
#include <mutex>

#include "../version.h"
#include "devM.hpp"
#include "misc.h"
#include "resolver.hpp"
#include "sys_var.hpp"
#include "dwld.hpp"
#include "dtu.hpp"
/**
 * 处理连接回调
 */
void devM_uv_cb_conn( uv_connect_t * req , int status )
{
	if( req == nullptr ) return;

	devManage::stConnectCmd * cmd = (devManage::stConnectCmd * )req->data;
	if( cmd == nullptr ) return;

	cmd->status = status;
	
	devManage * obj = cmd->obj;
	if( obj ){
		obj->OnConnect( cmd );
	}
}

void devM_uv_cb_recv( uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf )
{
	if( stream == nullptr ) return;
	if( buf == nullptr ) return;
	__show_line_1( "%s dev manager recv data %s" , TRED , TNORMAL );
	devManage * obj = ( devManage *)(stream->data);
	if( obj == nullptr ) return;
	
	if( nread > 0 ){   // 正常接收到数据
		obj->OnRecv( buf->base , nread );
	}else{ // 发生错误
		obj->OnNetError( nread );
	}
}

void devM_uv_cb_write( uv_write_t * req , int status )
{
	if( req == nullptr ) return;
	devManage :: stWriteCmd * cmd = ( devManage :: stWriteCmd *)( req->data );
	if( cmd == nullptr ){
		free( req );
		return;
	}

	devManage * obj = cmd->obj;
	obj->OnWrite( status );

	if( cmd->req ) free( cmd->req );
	if( cmd->buf.base ) free( cmd->buf.base );
	free( cmd );
}

void devM_uv_cb_shutdown( uv_shutdown_t * req , int status )
{
	if( req == nullptr ) return;
	
	devManage :: stWriteCmd * cmd = ( devManage :: stWriteCmd *)( req->data );
	
	if( cmd == nullptr ){
		free( req );
		return;
	}

	devManage * obj = cmd->obj;

	obj->OnShutdown( status );

	if( cmd->req ) free( cmd->req );
	free( cmd );
}

void devM_uv_cb_alloc( uv_handle_t* handle , size_t suggested , uv_buf_t * buf )
{
	devManage * obj = (devManage *) (handle->data );
	if( obj != nullptr ){
		buf->base = obj->GetBuffer();
		buf->len = 1024;
	}
}

void devM_uv_cb_close( uv_handle_t * handle )
{
	if( handle == nullptr ) return;
	devManage * obj = ( devManage *)( handle->data );

	if( obj == nullptr ) return;
	obj->OnClose( 0 );
}
//////////////////////////////////////////////////////////////////////////////////////////////////////

void devManage :: OnNetError( int e )
{

}

void devManage :: freeConnCmd( struct stConnectCmd * cmd )
{
	if( cmd == nullptr ) return;
	if( cmd -> req ) free( cmd->req );

	if( cmd->head ){
		uv_freeaddrinfo( cmd->head );
	}
}

void devManage :: initTCP( const std::string& server , int port )
{   
	if( server.empty() ){
		__show_line_1( "%s%s%s" , TRED , "Server address should not be empty" , TNORMAL );
		return;
	}
	if( port < 0 ){
		__show_line_1("%s%s%s" , TRED , "server port should not less zero." , TNORMAL );
		return;
	}
	uv_loop_t * p_loop = nullptr;
	try{ 
		p_loop = GetLooper()->get();
	}catch( ... ){
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "null pointer" , TNORMAL );
		return;
	}
	if( p_loop == nullptr ){
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "Can't get event loop" , TNORMAL );
		return;
	}
	if( m_tcp_handle.data != this ){  // 判断是否以经𥘉始完成，如果没有𥘉
		uv_tcp_init( p_loop , &m_tcp_handle );
		m_tcp_handle.data = this;
	}
	if( p_res ){
		delete p_res;
	}
	p_res = new resolver( server , port , true , [ this ](struct addrinfo *adds ){
		if( adds == nullptr ){
			__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "null pointer" , TNORMAL );
			m_reconn_timer.Start( -1 , true );
			return;
		}

		do_connect( nullptr , adds );
	} , [ this ]( int e ){        // 域名解析错误，找不到目标服务器, 然后重新尝试直到连接
		m_reconn_timer.Start( -1 , true );
	} );
}

void devManage :: do_connect( stConnectCmd * cmd1 , struct addrinfo * adds )
{
	if( adds == nullptr) return;
	stConnectCmd * cmd = cmd1;
	if( cmd1 == nullptr ) cmd = initConnCmd( adds );

	if( cmd ){
		int e = uv_tcp_connect( cmd->req , &m_tcp_handle , cmd->current->ai_addr , devM_uv_cb_conn );

		if( e ){
			__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "Connect remote fail" , TNORMAL );
			m_reconn_timer.Start( -1 , true );
			return;
		}

		m_conn_overtime.Start( -1, true );
	}else{
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "Allocate memory fail." , TNORMAL );
		return;
	}
}

void devManage :: OnConnect( struct stConnectCmd * cmd )
{
	if( cmd == nullptr ){
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "Connect command could not be null." , TNORMAL );
		return;
	}

	m_conn_overtime.Stop();

	if( cmd->status == 0 ){     // 连接成功
		m_connected = true;   

		uv_read_start( (uv_stream_t*)&m_tcp_handle , devM_uv_cb_alloc , devM_uv_cb_recv );
		// 开始进行身份验证
		do_login();
	}else{
		if( cmd->current->ai_next != nullptr ){ // 还有可以连接的地址
			cmd->current = cmd->current->ai_next;
			cmd->status = -1;

			do_connect( cmd , cmd->current );
		}else{  // 所有的地址都已经尝试，仍然无法连接
			m_reconn_timer.Start( -1 , true );
		}
	}
}

bool devManage :: parse( const char * data , size_t len , stDownPacket& rst)
{
	bool ret = false;
	if( crc8( data , len ) == true ){
		rst.head = data[ 0 ];                             // 
		rst.len = (uint16_t)( *(data + 9 ) );             // 𢿄个数据包的长度 
		rst.tail = data[ len - 1 ];                       // 包尾
		rst.crc = data[ len - 2 ];                         // 包CRC
		// 解析具体内容
		ret = parse_tlv( data + PACKET_DATA_POS , rst.len , rst );
	}
	return ret;
}

bool devManage :: parse_tlv( const char * data , size_t len , stPacket& pkg )
{
	bool ret = false;
	if( data == nullptr )   return ret;
	if( len == 0 )		return ret;
	
	size_t count = 0;
	count = caculate_down_packet_count( data , len );
	
	if( pkg.data == nullptr ){
		pkg.data = (stTLV*)malloc( sizeof( stTLV ) * count );
		memset( pkg.data , 0, sizeof( stTLV) * count );
	}

	if( pkg.data == nullptr ) return false;

	pkg.packet_count       = count;

	char           * tmp_p = ( char *)data;
	stTLV          * rst_p = pkg.data;
	size_t           i = 0;

	for( ; i < count && tmp_p < data + len; i ++ , rst_p ++){
		uint8_t tlv_len = *(uint8_t*)(tmp_p + 1);
		memcpy( rst_p , tmp_p , tlv_len + 2 );

		tmp_p = tmp_p + tlv_len + 2;
	}
	
	if( i < count && tmp_p >= data ){         // 数据结构不正确
		ret = false;
		free( pkg.data );
		pkg.data = nullptr;
	}else{
		ret = true;
	}
	return ret;
}

size_t devManage :: caculate_down_packet_count( const char * data , size_t len )
{
	size_t  ret = 0;
	if( data == nullptr ) return 0;
	if( len == 0 ) return 0;

	char * tmp_p = ( char *)data;
	uint8_t len1 = 0;
	while( (size_t)( tmp_p - data) < len ){
		len1 = *((uint8_t*) (tmp_p + 1 ) );
		ret ++;

		tmp_p = tmp_p + 2 + len1;
	}
	return ret;
}

devManage :: devManage( const std::string& server , int port )
:filterIO( filterIO::tail , nullptr ),m_buf( nullptr , []( char * p ){ if( p ) free( p ); })
{
	m_server    = server;
	m_port      = port;
	m_connected = false;
	p_res       = nullptr;
	m_run_time  = time( nullptr );

/// NOTE ： 注意，这段注释掉的代码在DTU应用使用
/*
	dtu * pt_dtu = GetOrCreateDTU();
	if( pt_dtu ){
		m_sn = pt_dtu->SN();
		m_imei = pt_dtu->GetIMEI();
		m_iccid = pt_dtu->GetICCID();
	}else{
		__show_line_1( "%sCan't retain DTU Module.%s" , TRED , TNORMAL );
		abort();
	}
*/
	std::shared_ptr< CSysVar > ptvar = GetOrCreateSysVar();
	if( ptvar ){
		ptvar->GetValue( "/SN" , m_sn );
		if( m_sn.empty() ){
			m_sn = "810190200002D446";
		}
		m_imei = "123456789012345";
		m_iccid = "543211234567890";

		ptvar->GetValue( "/devmanage/firmAddress" , m_firm_add );
		ptvar->GetValue( "/devmanage/firmPort" , m_firm_port );
	}
	/// NOTE(2019-2-20): 直接读设备时间可能不准，所以当拨号成功后应进行NTP同步
	m_time_start = time( nullptr );
	m_ntp_is_sync  = false;

	init_status();

	char * p = ( char *)malloc( 1024 );  
	if( p != nullptr ){
		m_buf.reset( p );
	}else{
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "Allocate memory fail." , TNORMAL );
		abort();                /// TODO : 因为内存分配失败是否要退出程序？
	}

	initTimer();
	initTCP( server , port );
}

devManage :: ~devManage()
{
}

void devManage :: initTimer()
{   
	std::shared_ptr< CSysVar > ptvar = GetOrCreateSysVar();
	if( ptvar ){
		ptvar->GetValue( "/devmanage/connKeepTime"  , CONN_KP_TIME  );
		ptvar->GetValue( "/devmanage/reConnTime"    , RECONN_TIME  );
		ptvar->GetValue( "/devmanage/connOvertime"  , CONN_OVERTIME );
		ptvar->GetValue( "/devmanage/comOvertime"   , COM_OVERTIME  );
		ptvar->GetValue( "/devmanage/reportTime"    , REPORT_TIME   );
		ptvar->GetValue( "/devmanage/heartTime"     , HEART_TIME    );
	}else{
		CONN_KP_TIME  = 60000;                      // 数据操作完后连接保持一分钟
		RECONN_TIME   = 60000 * 60;                 // 一个小时上线一次
		CONN_OVERTIME = 5000;                       // 连接超时时间
		COM_OVERTIME  = 5000;                       // 通讯超时间
		REPORT_TIME   = 60000 * 60 * 12;            // 12个小时作一次工况汇报
		HEART_TIME    = 10000;                      // 心跳
	}
	// 𥘉始化连接保持时间
	//m_conn_kp_time( CONN_KP_TIME );
	//m_conn_kp_time.SetOwner( [this]{ Close(); });
	// 𥘉始化重连时间
	
	m_reconn_timer( RECONN_TIME );
	m_reconn_timer.SetOwner( [this]{
		std::lock_guard< std::mutex> l( m_mutex );
		//initTCP( m_server , m_port );
	});
	// 𥘉始化连接超时时间
	m_conn_overtime( CONN_OVERTIME );
	m_conn_overtime.SetOwner( [ this ]{
		std::lock_guard< std::mutex> l( m_mutex );
		if( !m_connected ){
			initTCP( m_server , m_port );  
		}else{
			do_login();
		}
	});
	
	// 𥘉始化通讯超时时间
	m_com_overtime( COM_OVERTIME );
	m_com_overtime.SetOwner( [ this ]{ // 操作通讯超时，主状态和具体状态都恢复成READY
		if( m_com_status != comStatus :: STANDBY ){
			m_main_status               = mainStatus::READY;
			m_upgrade_status            = upgradeStatus::READY;
			m_status_report             = statusReport::READY;
			m_remote_setting_status     = remoteSetting::READY;
		}else{// 设备没有连接服务器
			m_main_status               = mainStatus::STANDBY;
			m_upgrade_status            = upgradeStatus::STANDBY;
			m_status_report             = statusReport::STANDBY;
			m_remote_setting_status     = remoteSetting::STANDBY;
		}

		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "communication fail." , TNORMAL );
	});
	
	// 𥘉始化工况汇报计时器
	m_report_timer( REPORT_TIME );
	m_report_timer.SetOwner( [ this ]{
		if( m_main_status == mainStatus :: READY ){
		m_main_status   = mainStatus :: REPORT;
		m_status_report = statusReport :: READY;
		}
		start_report();
	});

	// 𥘉始化工况汇报重新尝试计时器
	m_report_try_timer( 3000 );
	m_report_try_timer.SetOwner( [this]{
		if( m_main_status == mainStatus :: READY ){
			m_main_status   = mainStatus :: REPORT;
			m_status_report = statusReport :: READY;
		}
		std::lock_guard< std::mutex> l( m_mutex );
		start_report();
	});
	
	// 心跳计时器
	m_heart_timer( HEART_TIME );
	m_heart_timer.SetOwner([this]{
		__show_line_1("%sHeart is send%s", TGREEN , TNORMAL );
		std::lock_guard< std::mutex> l( m_mutex );
		heart_beat();
	});

}

void devManage :: init_status()
{
	m_main_status           = mainStatus::STANDBY;
	m_com_status            = comStatus::STANDBY;
	m_upgrade_status        = upgradeStatus::STANDBY;
	m_remote_setting_status = remoteSetting::remote_setting::STANDBY;
	m_status_report         = statusReport::STANDBY;
}

void devManage :: RunUpgrade( const std::string& ver )
{
	if( m_main_status == mainStatus :: READY ){
		m_main_status = mainStatus :: UPGRADE;

		do_query_upgrade( ver );
	}
}

void devManage :: OnRecv( const char * data , size_t len )
{
	if( data == nullptr || len == 0 ) return;

	if( m_com_status == comStatus::REQED ){
		m_com_status = comStatus::SVR_RESPED;
		m_com_overtime.Stop();
	}else if( m_com_status == comStatus::READY ){
		m_com_status = comStatus::CMD_RECVED;
		m_com_overtime.Stop();
	}else{ // 模块不是运行在可接受数据状态
		return;        
	} 

	stDownPacket packet;
	std::lock_guard< std::mutex> l( m_mutex );

	bool ok = parse( data , len , packet );
	if( !ok ){ return; }
	
	// 正确数据，按照协议执行相关指令
	if( is_resp( packet ) == true ){  // 处理响应
		dispatch_resp( packet );
	}else{                            // 处理指令
		dispatch_cmd( packet );
	}
}

bool devManage :: is_resp( const stDownPacket& packet )
{
	bool ret = true;
	
	if( packet.data->tag == 0xE6 ){ 
		ret = false; 
	}

	return ret;
}

void devManage :: dispatch_cmd( const stDownPacket & packet )
{
    	// 调用过滤器接口，把AT指令内容传递给AT指令引擎
    	filterIO::OnRecv( packet.data->len , ( char *)(packet.data->data) , filterIO::OK );
}

void devManage :: dispatch_resp( const stDownPacket & packet )
{
	switch( packet.data->tag ){
		case 0xc2:          // 设备登录返馈
		process_reg_resp( packet.data->len , ( char *)(packet.data->data ) );
		break;
		case 0xc9:          // 工况上报返馈
		process_report_resp( packet.data->len , (char *)(packet.data->data ));
		break;
		case 0xe7:          // 升级协商返馈
		process_upgrade_negtiation( packet.data->len , (char *)(packet.data->data) );
		break;
		default:break;
	}
}

void devManage :: process_reg_resp( size_t len , const char * data )
{
	m_reconn_timer.Stop();
	m_conn_overtime.Stop();

	//if( m_main_status != mainStatus :: STANDBY ) return;
	if( data == nullptr ) return;
	
	m_upgrade_pswd  = std::move( std::string( data ) );

	if( m_upgrade_pswd.length() == len ){
		__show_line_1( "Recv access password: %s%s.%s" , TBLUE , data , TNORMAL);
		m_main_status = mainStatus :: READY;

		m_heart_timer.Start( -1 , true );		// 起动心跳
		start_report();					// 起动工况汇报
	}else{
		m_upgrade_pswd.clear();
		__show_line_1( "%sUpgrade access password parse fail or bad response.%s" , TRED , TNORMAL );
		m_reconn_timer.Start( -1 , true );
	}
}

void devManage :: heart_beat()
{	
	try{
		stUpPacket   packet;
		if( initUpPacket( &packet ) == true ){
			char * p = to_raw( &packet );

			if( send( p , packet.len + PACKET_FIX_LEN ) == true ){/* 心跳数据发送成功 */
			}else{// 心跳数据发送失败 , 这种情况下多数是库错误
				__show_line_1( "%s%s%s" , TRED , "Send heart packet fail." , TNORMAL );
				abort();
			}
		}
	}catch( err_code e ){
		do_process_error( stFUNID::HEART , e );
	}catch( std::bad_alloc& e ){
		abort();
	}

	if( m_heart_timer.IsRuning() == true ){
		m_heart_timer.Reset();
	}else{
		m_heart_timer.Start( -1 , true );
	}
}

void devManage :: process_report_resp( size_t len , const char * data )
{
	if( m_main_status != mainStatus :: REPORT ) return;
	
	if( m_status_report == statusReport::REPORTED ){
		m_main_status = mainStatus :: READY;
		m_status_report = statusReport :: STANDBY;
		// 准备下次上报.
		m_report_timer.Start( -1 , true );
	}
}

bool devManage :: process_upgrade_req_resp( const std::string& resp )
{
	bool ret = false;
	if( m_upgrade_status == upgradeStatus::REQ ){
		ret = true;
		if( resp.find( "ERROR" ) != std::string::npos ){  // 请求升级无效
			m_upgrade_status = upgradeStatus::READY;
			return ret;
		}
		std::stringstream ss;
		std::string id , ver;
		std::regex reg( "(\\d+(\\.\\d+){3}),(\\w+)" );
		std::smatch sm;
		if( std::regex_search( resp , sm, reg ) == true ){
			id = sm[ 2 ];
			ss << m_firm_add << ":" << m_firm_port << "/" << id << "?q=" << m_upgrade_pswd  << "&sn=" << m_sn;

			do_download( ss.str() );
		}else{
			m_upgrade_status = upgradeStatus::READY;
		}
	}

	return ret;
}

bool devManage :: process_upgrade_start_resp( const std::string& resp )
{
	bool ret = false;
	if( m_upgrade_status == upgradeStatus::DOWNLOAD ){
		if( resp.find( "ERROR" ) != std::string::npos ){
			m_upgrade_status = upgradeStatus::READY;
			return ret;
		}

		ret = true;
	}

	return ret;
}

bool devManage :: process_upgrade_download_resp( const std::string& resp )
{
	bool ret = false;
	if( m_upgrade_status == upgradeStatus::INSTALL ){
		ret = true;
	}
	return ret;
}

void devManage :: process_upgrade_negtiation( size_t len , const char * data )
{
	if( m_main_status != mainStatus :: UPGRADE ) return;
	if( data == nullptr || len == 0 ){  // 
		return;
	}
	std::string str( data );
	str = str.substr( 0 , len );

	if( process_upgrade_req_resp( str ) == true ) return;

	if( process_upgrade_start_resp( str ) == true ) return;

	if( process_upgrade_download_resp( str ) == true ) return;
	if( process_upgrade_download_resp( str ) == true ) return;   
}

void devManage :: OnWrite( int status )
{// 
	std::lock_guard< std::mutex> l( m_mutex );
	switch( m_main_status.load() ){
		case mainStatus::STANDBY:
			m_com_status = comStatus::REQED;
		break;
		case mainStatus::READY: 
			do_on_write_main( status );
		break;
		case mainStatus::REMOTE_SET: 
			do_on_write_remote_set( status );
		break;
		case mainStatus::REPORT:
			//do_on_status_report( status );
		break;
		case mainStatus::UPGRADE:
			do_on_write_upgrade( status );
		break;
		default:break;
	}
    
	if( m_com_status == comStatus::READY ){// 如果通迅是在READY状态, 成功发送数据后
		// 检查回复时间
		m_com_status = comStatus::REQED;
		if( m_com_overtime.IsRuning() == true ){
			m_com_overtime.Reset();
		}else{
			m_com_overtime.Start( -1 , true );
		}
	}else{
		m_com_status = comStatus :: READY;
		m_com_overtime.Stop();
	}
}

void devManage :: OnShutdown( int status )
{
	m_heart_timer.Stop();
	if( status == 0 ){ // 
		if( m_is_destory == true ){
			uv_close( (uv_handle_t*)&m_tcp_handle , devM_uv_cb_close );
			init_status();          // 复位状态
		}
	}else{  // 关闭网络操作失败
		__show_line_1( "%s%s%s" , TRED , "SHUTDOWN device manage fail." , TNORMAL );
	}
}

void devManage :: do_login() 
{
	if( m_main_status != mainStatus :: STANDBY ) return;
	// 按照协议登录
	try{
		stUpPacket * packet = new stUpPacket();
		bool rst = initUpPacket( packet );

		if( rst ){
			std::string ver( AutoVersion :: FULLVERSION_STRING );
			// 构造数据包
			addUpTag( packet , TAG_FIRMWARE , ver.length() , ver.c_str() ); 
			char * p = to_raw( packet );
			__show_line_1( "\n%sTry login device manager server%s" , TGREEN , TNORMAL );
			// 发送数据包
			send( p , packet->len + PACKET_FIX_LEN );
			// 修改模块状态 
			wait_accept( CONN_OVERTIME );
			free( p );
			delete packet;
		}else{
			__show_line_1( "%s%s%s" , TRED , "Initializing data packet fail." , TNORMAL );
			abort();
		}
	}catch( std::bad_alloc& e ){
		abort();
	}
}

void devManage :: wait_accept( long overtime )
{
    	m_conn_overtime.Start( overtime , true );
}

bool devManage :: send( const char * data , size_t len )
{
	bool ret = false;
	if( m_connected == false ) return false;

	if( m_main_status != mainStatus :: READY ){
		m_heart_timer.Reset();
	}

	stWriteCmd  * cmd = ( stWriteCmd *)malloc( sizeof( stWriteCmd ));
	cmd->obj = this;
	cmd->req = ( uv_write_t *)malloc( sizeof(uv_write_t ) );
	cmd->req->data = cmd;

	cmd->buf.base = ( char *)malloc( len );
	cmd->buf.len = len;
	if( cmd->buf.base == nullptr ){
		free( cmd );
		cmd = nullptr;
	}else{
		memcpy( cmd->buf.base , data , len );
	}

	if( cmd ){
		int e = uv_write( cmd->req , (uv_stream_t*)&m_tcp_handle , &(cmd->buf ) , 1 , devM_uv_cb_write );
		ret = ( e >= 0 );

		if( e < 0 ){
			__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "libuv uv_write fail." , TNORMAL );
		}
	}
	
	return ret;
}

void devManage :: do_query_upgrade( const std::string& ver )
{
	stUpPacket packet;

	if( makeUpgradePacket( ver , packet ) == true ){
		try{
			char * p = to_raw( &packet ); 

			size_t len = packet.len + PACKET_FIX_LEN;
			if( send( p , len ) == true ){
				m_upgrade_status = upgradeStatus::REQ;
			}else{
				__show_line_1( "%sSend upgrade request fail.%s" , TRED , TNORMAL );
			}
		}catch( err_code e ){
			do_process_error( stFUNID::UPGRADE_REQ , e );
		}
	}else{
		__show_line_1( "%sConstruct upgrade request packet fail..%s" , TRED , TNORMAL );
	}
}

bool devManage :: makeUpgradePacket( const std::string& ver , stUpPacket& packet )
{
	try{
		if( initUpPacket( &packet ) == true ){
			std::string str( "AT+REQFW=" );
			
			if( ver.empty() == false ){ str = str + ver + "\r\n"; }
			else{ str = str + "?\r\n"; }

			addUpTag( &packet , TAG_UPGRADE , str.length() , str.c_str() );
			return true;
		}
	}catch( err_code e ){
		do_process_error( stFUNID::MAKE_UPPACKET , e );
	}

	return false;
}

void devManage :: do_process_error( stFUNID::funID id , err_code e )
{
	switch( id ){
		case stFUNID::UPGRADE_DOWNLOAD:
			__show_line_1( "%sFail download upgrade package%s" , TRED , TNORMAL );
		break;
		case stFUNID::UPGRADE_REQ:
			__show_line_1( "%sFail request upgrade%s" , TRED , TNORMAL );
		break;
		case stFUNID::UPGRADE_INSTALL:
			__show_line_1( "%sFail intall file during upgrading%s" , TRED , TNORMAL );
		break;
		case stFUNID::REMOTE_SETTING:
			__show_line_1( "%sFail execute remote setting%s" , TRED , TNORMAL );
		break;
		case stFUNID::REPORT_START:
			__show_line_1( "%sFail start report%s" , TRED , TNORMAL );
		break;
		case stFUNID::MAKE_UPPACKET:
			__show_line_1( "%sFail make up packet%s" , TRED , TNORMAL );
		break;
		default:break;
	}
}

void devManage :: do_install()
{
	// 解压文𢓐
	system( "cd /usrdata");
	system( "rm -rf dtu" );
	system( "tar -jvf dtu.tar.gz" );
	// 修改配置文𢓐SN
	if( access( "/usrdata/dtu/config.xml" , F_OK ) == 0 ){
		std::shared_ptr< CSysVar > ptvar = GetOrCreateSysVar( "/usrdata/dtu/config.xml" );
		ptvar->SetValue( "/SN" , m_sn );
		ptvar->Save( "/usrdata/dtu/config.xml" );
		sync();
	}
	// 安装
	if( access( "/userdata/dtu/install" , F_OK ) == 0 ){
		system( "chmod +x install" );
		if( access( "/usrdata/dtu/dtu" , F_OK ) == 0 ){
			system( "cp /usrdata/dtu/* /data" );
			system( "cd /data" );
			system( "./install" );
		}else{
			failDownload();
		}
	}else{
		failDownload();
	}
}


void devManage :: Destory()
{
	m_is_destory = true;
	Close();
}

void devManage :: Close()
{
	stCloseCmd  * p_cmd = ( stCloseCmd *)malloc( sizeof( stCloseCmd ));
	if( p_cmd ){
		p_cmd->req = ( uv_shutdown_t *)malloc( sizeof( uv_shutdown_t ));
		if( p_cmd -> req  == nullptr ){
			free( p_cmd );
			p_cmd = nullptr;
			throw ERR_ALLOC_MEM;
			return;
		}

		p_cmd->obj = this;
		p_cmd->req->data = p_cmd;
	}else{
		throw ERR_ALLOC_MEM;
		return;
	}

	//m_conn_kp_time.Stop();                      // 连接保持时间
	m_reconn_timer.Stop();                      // 重连时间
	m_conn_overtime.Stop();                     // 连接超时时间
	m_com_overtime.Stop();
	
	m_connected = false;

	int e = uv_read_stop( (uv_stream_t*)&m_tcp_handle );
	if( e ){
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "libuv read stop fail." , TNORMAL );
	}else{ return; }
		e = uv_shutdown( p_cmd->req , (uv_stream_t*)&m_tcp_handle , devM_uv_cb_shutdown );
	if( e ){
		__show_line_1( "%s%s%s%s%s" , TBLUE , __PRETTY_FUNCTION__ , TRED , "libuv shutdown fail." , TNORMAL );
	}
}

void devManage :: OnClose( int status )
{
	if( m_is_destory == true ){
		delete this;
	}else{
		// 临时关闭通道
		m_main_status = mainStatus :: STANDBY;
		m_upgrade_status = upgradeStatus::STANDBY;
		m_status_report = statusReport::STANDBY;
		m_remote_setting_status = remoteSetting::STANDBY;
	}
}

void devManage :: finishInstall()
{
	stUpPacket packet;
	try{
		if( initUpPacket( &packet ) == true ){
			std::string cmd;

			cmd = "AT+UPFW=FINISH\r\n";
			addUpTag( &packet , TAG_UPGRADE , cmd.length() , cmd.c_str() );

			char * data = to_raw( &packet );
			if( send( data , packet.len + PACKET_FIX_LEN ) == true ){
				free( data );
				m_upgrade_status = upgradeStatus::DOWNLOAD;
			}else{
				m_upgrade_status = upgradeStatus::READY;
			}

			m_upgrade_status = upgradeStatus::STANDBY;
			m_main_status = mainStatus::READY;
		}
	}catch( err_code e ){
		m_upgrade_status = upgradeStatus::STANDBY;
		m_main_status = mainStatus::READY;
		do_process_error( stFUNID::UPGRADE_DOWNLOAD , e );
	}
}

void devManage :: failDownload()
{
	stUpPacket packet;
	try{
		if( initUpPacket( &packet ) == true ){
			std::string cmd;

			cmd = "AT+UPFW=FAILED\r\n";
			addUpTag( &packet , TAG_UPGRADE , cmd.length() , cmd.c_str() );

			char * data = to_raw( &packet );
			if( send( data , packet.len + PACKET_FIX_LEN ) == true ){
				free( data );
				m_upgrade_status = upgradeStatus::DOWNLOAD;
			}else{
				m_upgrade_status = upgradeStatus::STANDBY;
			}

			m_main_status = mainStatus::READY;
		}
	}catch( err_code e ){
		m_upgrade_status = upgradeStatus::STANDBY;
		do_process_error( stFUNID::UPGRADE_DOWNLOAD , e );
	}
}

void devManage :: startDownload()
{
	try{
		stUpPacket packet;
		if( initUpPacket( &packet ) == true ){
			std::string cmd;

			cmd = "AT+UPFW=START\r\n";
			addUpTag( &packet , TAG_UPGRADE , cmd.length() , cmd.c_str() );

			char * data = to_raw( &packet );
			if( send( data , packet.len + PACKET_FIX_LEN ) == true ){
				free( data );
				m_upgrade_status = upgradeStatus::DOWNLOAD;
			}else{
				m_upgrade_status = upgradeStatus::READY;
			}
		}
	}catch( err_code e ){
		m_upgrade_status = upgradeStatus::READY;
		do_process_error( stFUNID::UPGRADE_DOWNLOAD , e );
	}catch( std::bad_alloc& e ){
		__show_line_1( "%sAlloc Download request packet fail.%s" , TRED , TNORMAL );
		abort();
	}
}

void devManage :: do_download( const std::string& file )
{
	try{
		Downloader download( file , "/usrdata/dtu.tar.gz" );
		// 设置下载完成处理
		download.onFinish( [this]( Downloader::err_code e ){
			if( e == Downloader::OK ){
				// 执行安装
				do_install();
				// 回复服务器下载完成
				finishInstall();
				// 重新启动
				reboot( RB_AUTOBOOT );
			}else{
				// 回复服务器下载失败
				failDownload();
			}
		});
		startDownload();// 通知服务器开始下载文𢓐

		download.Run(); // 启动下载
	}catch( Downloader::err_code e ){
		// 回复服务器下载失败
		failDownload();
	}
}

bool devManage :: initUpPacket( stUpPacket * packet , int count )
{
	bool ret = false;

	if( packet == nullptr ) return false;

	packet ->data           = ( stTLV *)malloc( sizeof( stTLV ) * count );
	if( packet-> data == nullptr ) throw ERR_ALLOC_MEM;
	packet -> packet_count  = count;
	packet -> current_count = 0;
	packet->len             = 0;
	packet->head            = 0x5a;
	packet->tail            = 0xa5;

	if( !m_sn.empty() ){

		size_t len = m_sn.length();
		len = ( len >> 1 ) + ( len & 0x1 );

		uint8_t * p = nullptr;
		p = ( uint8_t *)malloc( len );

		if( p ){
			ret = str2hex4bit( m_sn , p );
			memcpy( packet->sn , p , len);
			free( p );

			ret = true;
		}else{
			throw ERR_ALLOC_MEM;
		}
		
	}else{
		__show_line_1("%smissing SN.%s", TRED , TNORMAL );
	}

	return ret;
}

uint8_t devManage :: makeCRC8( const char * data , size_t len )
{
	if( data == nullptr ) throw ERR_NULL_DATA;
	uint8_t crc = 0x00;
	char * buf = ( char *)data;
	while (len-- != 0){
		crc = crc ^ (*buf);

		for (int i = 0;i < 8; i++) {
			if ((crc & 0x80) != 0) {
				crc *= 2; 
				crc ^= 0xE5;
			} 
			else crc *= 2;
		}
		buf++;
	}
	return 0;
	//return crc;
}

uint8_t devManage :: crc8( const stUpPacket * packet )
{
	char        * data = nullptr;
	size_t        len = 0;

	if( packet == nullptr ) throw ERR_NULL_POINTER;
	// 计算长度
	len = packet->len + sizeof( stUpPacket ) - 2 * sizeof( int ) - sizeof( stTLV *) - 2;
	
	data = ( char *)malloc( len );
	if( data == nullptr ) throw ERR_ALLOC_MEM;

	memcpy( data , packet , PACKET_DATA_POS );
	memcpy( data + PACKET_DATA_POS , packet -> data , len - PACKET_DATA_POS );

	uint8_t ret = 0;// makeCRC8( data , len );

	free( data );

	return ret;
}

char * devManage :: to_raw( const stUpPacket * packet )
{
	char * data = nullptr;
	size_t len = 0;
	if( packet == nullptr ) throw ERR_NULL_POINTER;
	// 计算长度
	len = packet->len + sizeof( stUpPacket ) - 2 * sizeof( int ) - sizeof( stTLV *);
	// 
	data = ( char *)malloc( len );
	if( data == nullptr ) throw ERR_ALLOC_MEM;

	memcpy( data , packet , PACKET_DATA_POS );

	memcpy( data + PACKET_DATA_POS , packet -> data , len - PACKET_DATA_POS );

	memcpy( data + packet->len + PACKET_DATA_POS , &(packet->crc) , 2 );

	return data;
}

bool devManage :: crc8( const char * data , size_t len )
{
	if( data == nullptr ){ throw ERR_NULL_POINTER; }
	if( len == 0 ){ throw ERR_EMPTY_DATA; }

	bool ret = false;
	uint8_t crc1 = data[ len - 2 ] , crc2 = 0;

	crc2 = makeCRC8( data , len - 2 );

	ret = (crc1 == crc2 );

	return ret;
}

bool devManage :: on_forward( size_t len , const char * data , err_code &err , size_t& rlen , char ** rd )
{
	bool ret = false;
	if( data != nullptr ){
		if( m_main_status == mainStatus :: REMOTE_SET ){
			if( m_remote_setting_status == remoteSetting::RUNING ){
				std::string str( data );
				str = std::move( str.substr(0 , len ) );
				m_remote_setting_status = remoteSetting::RESPED;
				finish_setting( str );
			}
		}
	}

	*rd = ( char *)data;
	rlen = len;
	return ret;
}

bool devManage :: on_backward( size_t len , const char * data , err_code &err , size_t& rlen , char ** rd  )
{
	bool ret = false;
	if( data != nullptr ){
		OnRecv( data , len );
	}

	*rd = ( char *)data;
	rlen = len;

	return ret;
}

void devManage :: on_disconnect_of_main_status()
{
    	m_main_status = mainStatus::STANDBY;
}

void devManage :: on_connected_of_main_status()
{
    	m_main_status = mainStatus::READY;
}

void devManage :: start_setting()
{
    	m_main_status = mainStatus :: REMOTE_SET;
}

void devManage :: finish_setting( const std::string& resp )
{
	stUpPacket packet;
	try{
		if( initUpPacket(&packet ) == true ){
			addUpTag( &packet , TAG_REMOTE_SET , resp.length() , resp.c_str() );
			char * data = to_raw( &packet );
			if( send( data , packet.len + PACKET_FIX_LEN ) == true ){
				if( m_remote_setting_status == remoteSetting::RESPED )
				m_remote_setting_status = remoteSetting::READY;
			}else{
				m_remote_setting_status = remoteSetting::STANDBY;
			}
		}
	}catch( err_code e ){
		do_process_error( stFUNID::REMOTE_SETTING , e );
	}

}

void devManage :: start_report()
{
	if( m_main_status != mainStatus::READY && m_main_status != mainStatus :: REPORT ){
		m_report_try_timer.Stop();
		m_report_try_timer.Start( -1 , true );
		return;
	}
	
	stUpPacket packet;
	try{
		if( initUpPacket( &packet , 5 ) == true ){
			uint8_t * p = ( uint8_t *)malloc( 1024 );
			// IMEI 
			size_t len = papreIMEI( p );			
			addUpTag( &packet , TAG_IMEI , len , p );
			// ICCID
			//memset( p , 0 , 1024 );
			len = papreICCID( p );
			addUpTag( &packet , TAG_ICCID , len , p );
			// 信号
			//memset( p , 0 , 1024 );
			len = papreSignal( p );
			addUpTag( &packet , TAG_SIGNAL , len , p );
			// 故障码
			len = papreErrorCode( p );
			addUpTag( &packet , TAG_ERR_CODE , len , p );
			// 运行时间
			len = papreRunningTime( p );
			addUpTag( &packet , TAG_RUNNING_TIME , len , p );
			
			if( p ) free( p );
			p = nullptr;

			char * data = to_raw( &packet );
			
			if( send( data , packet.len + PACKET_FIX_LEN ) == true ){
				m_status_report = statusReport::REPORTED;
			}else{
				m_report_try_timer.Start( -1 , true );
			}
		}
	}catch( err_code e ){
		__show_line_1( "%sERROR OCCURED: %d %s" ,TRED , e , TNORMAL);
		m_report_try_timer.Start( -1 , true );
		do_process_error( stFUNID::REPORT_START , e );
	}
}

void devManage :: finish_report()
{
}

void devManage :: timeSync()
{
	system( "ntpd -b" );  // 

	if( m_ntp_is_sync == false ){
		std::thread thd([ this ]{
			std::this_thread::yield();
			std::this_thread::sleep_for( std::chrono::seconds( 5 ) );

			system( "hwclock -w" );				// 修改硬𢓐时钟
			m_time_start = time( nullptr );			// 读取当前时间
			
			m_ntp_is_sync = true;				// 记录更新标记
		});

		thd.detach();
	}
}

devManage :: stConnectCmd * 
devManage :: initConnCmd( struct addrinfo * info )
{
	stConnectCmd * ret = nullptr;
	if( info == nullptr ) return ret;
	try{
		ret = new stConnectCmd();
		
		ret->head = info;
		ret->current = info;
		ret->obj = this;

		ret->req = ( uv_connect_t *)malloc( sizeof( uv_connect_t) );
		if( ret->req == nullptr ){
			uv_freeaddrinfo( info );
			free( ret );
			ret = nullptr;
			throw ERR_ALLOC_MEM;
		}

		ret->req->data = ret;
	}catch( std::bad_alloc & e ){
		ret = nullptr;
		__show_line_1("%s%s%s" , TRED , "allocate memory fail." , TYELLOW );
	}
	
	return ret;
}

void devManage :: do_on_write_remote_set( int status )
{

}

void devManage :: do_on_write_main( int status )
{

}

void devManage :: do_on_write_upgrade( int status )
{
    
}

size_t devManage :: papreIMEI( uint8_t * rst )
{
	size_t ret = 0;
	if( rst == nullptr ) throw ERR_NULL_POINTER;
	std::string str;

	if( m_imei.empty() ){
		dtu * pdtu = GetOrCreateDTU();
		if( pdtu == nullptr ) throw ERR_NULL_DTU;

		str = pdtu->GetIMEI( );
	}else{
		str = std::move( m_imei );
	}

	if( str2hex4bit( str , rst ) == false ){
		throw ERR_IMEI_CONVERT;
	}

	ret = str.length();
	ret = ( ret >> 1 ) + ( ret & 0x1 );
	
	m_imei = std::move( str );

	return ret;
}

size_t devManage :: papreICCID( uint8_t * rst )
{
	size_t ret = 0;
	if( rst == nullptr ) throw ERR_NULL_POINTER;
	std::string str;
	if( m_iccid.empty() == true ){
		dtu * pdtu = GetOrCreateDTU();
		if( pdtu == nullptr ) throw ERR_NULL_DTU;

		str = pdtu->GetICCID( );
	}else{
		str = std::move( m_iccid );
	}

	if( str2hex4bit( str , rst ) == false ){
		throw ERR_ICCID_CONVERT;
	}

	ret = str.length();
	ret = ( ret >> 1 ) + ( ret & 0x1 );

	m_iccid = std::move( str );

	return ret;
}

size_t devManage :: papreSignal( uint8_t * rst )
{
	size_t ret = 0;
	if( rst == nullptr ) throw ERR_NULL_POINTER;
	int csq = -99;
	QL_NW_GetCSQ( &csq );
	ret = 1;
	rst[ 0 ] = (uint8_t)(csq );

	return ret;
}

size_t devManage :: papreErrorCode( uint8_t * rst )
{
	size_t ret = 0;
	if( rst == nullptr ) throw ERR_NULL_POINTER;
	
	dtu * p_dtu = GetOrCreateDTU();
	if( p_dtu ){
		int err = p_dtu->GetErrorCode();
		uint16_t * p = ( uint16_t *)rst;
		p[ 0 ] = (int16_t) err;
		ret = 2;
	}else{
		ret = 0;
	}
	return ret;
}

size_t devManage :: papreRunningTime( uint8_t * rst )
{
	size_t ret = 0;
	if( rst == nullptr ) throw ERR_NULL_POINTER;
	
	ret = 2;
	
	time_t t1 = time( nullptr );
	t1 = t1 - m_run_time;
	t1 /= 1000;			// s
	t1 /= 60;			// HOUR
	
	uint16_t * p = (uint16_t*)rst;
	p[ 0 ] = (uint16_t)t1;

	return ret;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

devManage  * globeDevManage = nullptr;

devManage * GetOrCreateDevManager()
{
	devManage  * ret = nullptr;
	if( globeDevManage != nullptr ) ret = globeDevManage;
	else{
		std::string svr;
		int port;
		std::shared_ptr< CSysVar > ptvar = GetOrCreateSysVar();
		if( ptvar ){
			ptvar->GetValue( "/devm_svr" , svr );
			ptvar->GetValue( "/devm_port" , port );
		}else{
			svr = "117.78.33.204";
			port = 10008;
		}
		ret = new devManage( svr , port );
	}
	return ret;
}